package org.nobody.mallb2c.mallorder.controller;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.nobody.common.utils.R;
import org.nobody.mallb2c.mallorder.entity.OrderEntity;
import org.nobody.mallb2c.mallorder.entity.OrderReturnReasonEntity;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.Date;
import java.util.UUID;

/**
 * @author 3489309323@qq.com
 * @create 2020-09-21-14:13
 */
@RabbitListener(queues = {"hello-java-queue"})
@RestController
@Slf4j
public class RabbitController {

  @Autowired
  RabbitTemplate rabbitTemplate;

  @GetMapping("/sendMq")
  public String sendMq(@RequestParam(value = "num",defaultValue = "10") Integer num) {
    for (int i = 0; i < 10; i++) {
      if (i % 2 == 0) {
        OrderReturnReasonEntity reasonEntity = new OrderReturnReasonEntity();
        reasonEntity.setId(1L);
        reasonEntity.setCreateTime(new Date());
        reasonEntity.setName("哈哈-" + i);

        //rabbitTemplate.convertAndSend("hello-java-exchange","hello.java",reasonEntity);
        rabbitTemplate.convertAndSend("hello-java-exchange", "hello.java", reasonEntity, /*→ 可选,指定消息的唯一id*/new CorrelationData(UUID.randomUUID().toString()));

        log.info("消息发送完成{}",reasonEntity);
      }else{
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(UUID.randomUUID().toString());
        //rabbitTemplate.convertAndSend("hello-java-exchange","hello.java",orderEntity);

        /**↓ 测试rabbitTemplate.setReturnCallback， 未投递到queue时的回调*/
        rabbitTemplate.convertAndSend("hello-java-exchange","hello222.java",orderEntity,/*→ 可选,指定消息的唯一id*/ new CorrelationData(UUID.randomUUID().toString()));
      }
    }
    return "ok";
  }

  /**
   * queues: 声明需要监听的所有队列
   *
   * message类型为 class org.springframework.amqp.core.Message
   *
   * 参数可以为以下类型
   * 1. Message message 原生消息详细信息。 头+体
   * 2. T<发送的消息的类型>, 比如 OrderReturnReasonEntity content
   * 3. Channel channel: 当前传输数据的通道
   *
   * Queue(destination为point to point): 可以很多人来监听。 只要收到消息, 队列就会删除消息, 而且只能有一个人收到此消息。
   *   1) 订单服务启动多个: 同一个消息,只能有一个客户端收到
   *   2）只有一个消息完全处理完,方法运行结束. 我们才可以接受到下一个消息
   */


  /** case1 */
//  @RabbitListener(queues = {"hello-java-queue"/*,""*/})
//  public void receiveMessageTest(Message message, OrderReturnReasonEntity content, Channel channel/*←当前传输数据的通道*/){
//    System.out.println("接受到消息: " + message + " ===>类型: " + message.getClass());
//
//
//    //消息体
//    byte[] body = message.getBody(); //原生消息体, 我们想要获得发送时的那个类型,可以直接使用下面的方式
//    System.out.println("content ===> " + content); //content ===> OrderReturnReasonEntity(id=1, name=哈哈, sort=null, status=null, createTime=Mon Sep 21 13:35:51 CST 2020)
//
//    //消息头属性信息
//    MessageProperties messageProperties = message.getMessageProperties();
//  }

  /** case2 */
  /**
   * 测试发消息 用多台同种微服务服务器接受消息
   * 即使是这种情况,同一个消息, 也只能有一个客户端接受到
   *
   * 注意 由于这里这样使用了单元测试 会多启动一个微服务实例 也就是说单元测试这里也会吃掉几个消息
   */
//  @RabbitListener(queues = {"hello-java-queue"})
//  public void receiveMessageTest2(Message message, OrderReturnReasonEntity content, Channel channel){
//    System.out.println("content ===> " + content);
//  }

  /** case3 */
  /**
   * 只有一个消息完全处理完,方法运行结束.
   * 我们才可以接受到下一个消息
   *
   */
  //@RabbitListener(queues = {"hello-java-queue"})
  @RabbitHandler
  public void receiveMessageTest3(Message message, OrderReturnReasonEntity content, Channel channel) throws InterruptedException {
    System.out.println("接受到消息 ===> " + content);
    //Thread.sleep(3000);
    System.out.println("接受到完成 ===> " + content.getName());

    //deliveryTag ==> channel内按顺序自增的
    long deliveryTag = message.getMessageProperties().getDeliveryTag();

    try {
      if (deliveryTag % 2 == 0) {
        //签收货物, 非批量模式
        /**tip*/
        //用debug貌似 无法正确测试此例
        channel.basicAck(deliveryTag, false/*只签收当前这个货物,做一个确认一个*/);
        System.out.println("签收了货物... deliveryTag为：" + deliveryTag);
      }else{
        //退货
        //long deliveryTag, boolean multiple, boolean requeue
        channel.basicNack(deliveryTag,false,true/*如果为true会重新发回MQ重新入队,如果为false会直接丢弃*/);
        //long deliveryTag, boolean requeue
        //channel.basicReject();
        System.out.println("没有签收货物... deliveryTag为：" + deliveryTag);
      }

    } catch (IOException e) {
      //网络中断
      e.printStackTrace();
    }
  }

  /** case4 */
  /**
   * 测试不同消息实体类型 用不同重载方法来接受
   */
  //@RabbitListener(queues = {"hello-java-queue"}) //← 或则标注在类上,然后接消息到底要靠哪个方法接,就用@RabbitHandler进行标注
//  @RabbitHandler
//  public void receiveMessageTest4(Message message, OrderReturnReasonEntity content, Channel channel) throws InterruptedException {
//    System.out.println("receiveMessageTest4 接受到消息 ===> " + content);
//  }

  // 注意有可能这里控制台显示不出来,是因为使用的是单元测试进行测试, 被单元测试吃掉了, 在单元测试的控制台里
//  @RabbitHandler
//  public void receiveMessageTest5(OrderEntity content) throws InterruptedException {
//    System.out.println("receiveMessageTest5 接受到消息 ===> " + content);
//  }
}
